package com.weilive.pay.service.weix;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.weilive.core.utils.HttpUtils;
import com.weilive.core.utils.MD5Utils;
import com.weilive.core.utils.XPathHelper;
import com.weilive.pay.dao.mapper.UserCashMapper;
import com.weilive.pay.dao.model.AddEMoney;
import com.weilive.pay.dao.model.CashLog;
import com.weilive.pay.dao.model.CashTx;
import com.weilive.pay.dao.model.UserCash;
import com.weilive.pay.dao.model.UserInfo;
import com.weilive.pay.msg.ToPayMsg;
import com.weilive.pay.service.CashTemplate;

@Service
public class WxPayService {

	private static final Logger logger = LoggerFactory.getLogger(WxPayService.class);

	@Autowired
	private UserCashMapper userCashDao;
	// 付费资源
	@Autowired
	private CashTemplate cashTemplate;

	private String getLogKey(String key) {
		try {
			return MD5Utils.encryptToHex(key);
		} catch (Exception e) {
		}
		return UUID.randomUUID().toString();
	}

	// 没用事物
	public String checkAndSaveLog(Map<String, String> params) {
		try {
			// 交易状态
			String return_code = params.get("return_code");
			if (return_code.equals("FAIL")) {
				logger.info("支付忽略,return_code=" + return_code);
				return "ok";
			}
			// 内容
			String body = params.get("attach");
			String userId = "none";
			if (body != null) {
				JSONObject obj = (JSONObject) JSONObject.parse(body);
				userId = obj.getString("userId");
			}
			String key = getLogKey(params.toString());

			CashLog log = userCashDao.getCashLog(key);
			if (log == null) {
				log = new CashLog();
				log.setId(key);
				log.setRecipe(params.toString());
				log.setUser_id(Long.parseLong(userId));
				log.setStatus(0);
				userCashDao.saveCashLog(log);
			}
			// 已到账
			if (log.getStatus() == 1) {
				// 支付成功了
				return "ok";
			}
		} catch (Exception e) {
		}

		return "fail";
	}

	@Transactional
	public String pay(Map<String, String> params) {

		String result_code = params.get("result_code");
		if (result_code.equals("FAIL")) {
			// 失败了直接返回
			logger.info("支付错误=" + result_code);
			return "ok";
		}
		String sign = params.get("sign");

		String toSign = getSign(params);

		if (!toSign.equals(sign)) {
			return "sign验证错误";
		}

		String logKey = getLogKey(params.toString());

		// 商户订单号
		String out_trade_no = params.get("out_trade_no");
		// 微信交易号
		String transaction_id = params.get("transaction_id");

		String goodsCount = "1";

		String price = "0";
		String total_fee = params.get("total_fee");
		String seller_id = params.get("mch_id");
		String seller_email = "";
		String buyer_id = "";
		String buyer_email = "";
		// 内容
		String body = params.get("attach");

		JSONObject obj = (JSONObject) JSONObject.parse(body);
		String userId = obj.getString("userId");
		String goodsId = obj.getString("produceId");
		UserCash userCash = userCashDao.getUserCash(out_trade_no);

		// 加钱操作,单位分
		double costMoney = Double.parseDouble(total_fee) / 100d;// 花费的rmb
		if (userCash == null) {
			userCash = new UserCash();
			userCash.setOutTradeNo(out_trade_no);
			userCash.setTradeNo(transaction_id);
			userCash.setUserId(Long.parseLong(userId));
			userCash.setGoodsId(goodsId);
			userCash.setGoodsCount(goodsCount);
			userCash.setPrice(Double.parseDouble(price));
			userCash.setTotalFee(costMoney);
			userCash.setSellerId(seller_id);
			userCash.setSellerEmail(seller_email);
			userCash.setBuyerId(buyer_id);
			userCash.setBuyerEmail(buyer_email);
			userCash.setPayStatus(1);
			userCash.setExt("Wxpay");
			userCash.setCdate(new Date());
			userCashDao.insertSelective(userCash);

			int mibi = Math.max(1, (int) (costMoney * 10));
			CashTx cashTx = cashTemplate.getCashTx(goodsId);
			if (cashTx != null) {
				double ratio = cashTx.getCredit() / cashTx.getCost();
				if (costMoney == cashTx.getCost()) {
					mibi = cashTx.getCredit();
				} else {
					mibi = Math.max(1, (int) (costMoney * ratio));
				}
			}
			// call add_e_money(userId, mibi)
			AddEMoney result = userCashDao.addEMoney(Long.parseLong(userId), (long) mibi, userCash.getTradeId());

			userCashDao.useCashSuccess(logKey);

			logger.info("userId={},用户可得mibi={}, out_trade_no={}", new Object[] { userId, mibi, out_trade_no });

			if (result.getIs_success_flag().equals("N")) {
				throw new RuntimeException(result.getErr_msg());
			}
		}
		return "ok";
	}

	private String queryPay(Map<String, String> params) {
		// 交易状态
		String return_code = params.get("return_code");
		if (return_code.equals("FAIL")) {
			logger.info("支付忽略,return_code=" + return_code);
			return "支付失败";
		}
		String result_code = params.get("result_code");
		if (result_code.equals("FAIL")) {
			// 失败了直接返回
			logger.info("支付错误=" + result_code);
			return "支付错误";
		}
		String trade_state = params.get("trade_state");

		if (!trade_state.equals("SUCCESS")) {
			// 失败了直接返回
			logger.info("支付失败=" + trade_state);
			return "支付失败";
		}
		String sign = params.get("sign");

		String toSign = getSign(params);

		if (!toSign.equals(sign)) {
			return "sign验证错误";
		}

		String logKey = getLogKey(params.toString());

		// 商户订单号
		String out_trade_no = params.get("out_trade_no");
		// 微信交易号
		String transaction_id = params.get("transaction_id");

		String goodsCount = "1";

		String price = "0";
		String total_fee = params.get("total_fee");
		String seller_id = params.get("mch_id");
		String seller_email = "";
		String buyer_id = "";
		String buyer_email = "";
		// 内容
		String body = params.get("attach");

		JSONObject obj = (JSONObject) JSONObject.parse(body);
		String userId = obj.getString("userId");
		String goodsId = obj.getString("produceId");
		// String userName = obj.getString("userAlias");
		UserCash userCash = userCashDao.getUserCash(out_trade_no);
		if (userCash == null) {
			userCash = new UserCash();
			userCash.setOutTradeNo(out_trade_no);
			userCash.setTradeNo(transaction_id);
			userCash.setUserId(Long.parseLong(userId));
			userCash.setGoodsId(goodsId);
			userCash.setGoodsCount(goodsCount);
			userCash.setPrice(Double.parseDouble(price));
			userCash.setTotalFee(Double.parseDouble(total_fee));
			userCash.setSellerId(seller_id);
			userCash.setSellerEmail(seller_email);
			userCash.setBuyerId(buyer_id);
			userCash.setBuyerEmail(buyer_email);
			userCash.setPayStatus(1);
			userCash.setExt("Wxpay");
			userCash.setCdate(new Date());
			userCashDao.insertSelective(userCash);
			// 加钱操作,单位分
			int mibi = Math.max(1, (int) ((Double.parseDouble(total_fee) / 100d) * 10));
			CashTx cashTx = cashTemplate.getCashTx(goodsId);
			if (cashTx != null) {
				if ((Double.parseDouble(total_fee) / 100d) == cashTx.getCost()) {
					mibi = cashTx.getCredit();
				}
			}
			// call add_e_money(userId, mibi)
			AddEMoney result = userCashDao.addEMoney(Long.parseLong(userId), (long) mibi, userCash.getTradeId());

			userCashDao.useCashSuccess(logKey);

			logger.info("userId={},用户可得mibi={}, out_trade_no={}", new Object[] { userId, mibi, out_trade_no });

			if (result.getIs_success_flag().equals("N")) {
				throw new RuntimeException(result.getErr_msg());
			}
		}
		return "ok";
	}

	/**
	 * 获取参数验签
	 * 
	 * @param map
	 * @return
	 * @throws Exception
	 */
	public static String getSign(Map<String, String> map) {
		List<String> list = new ArrayList<String>();

		for (Entry<String, String> entry : map.entrySet()) {
			if (entry.getKey().equals("sign")) {
				continue;
			}
			if (entry.getValue() != null && !entry.getValue().equals("")) {
				list.add(entry.getKey() + "=" + entry.getValue() + "&");
			}
		}

		int size = list.size();
		String[] arrayToSort = list.toArray(new String[size]);
		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < size; i++) {
			sb.append(arrayToSort[i]);
		}
		String result = sb.toString();
		result += "key=" + WxPayConfig.APP_KEY;

		try {
			result = MD5Utils.encryptToHex(result).toUpperCase();
		} catch (Exception e) {
			result = "";
		}
		return result;
	}

	@Transactional
	public String query(String out_trade_no) throws Exception {
		UserCash userCash = userCashDao.getUserCash(out_trade_no);

		if (userCash == null) {
			Map<String, String> map = new HashMap<String, String>();
			map.put("appid", WxPayConfig.APP_ID);
			map.put("mch_id", WxPayConfig.MCH_ID);
			map.put("out_trade_no", out_trade_no);
			map.put("nonce_str", UUID.randomUUID().toString().replace("-", "").toLowerCase());

			String sign = getSign(map);

			map.put("sign", sign);

			// 去微信查询
			String toXml = XPathHelper.toXmlNode(map);

			String result = HttpUtils.HttpPostGo(WxPayConfig.PAY_QUERY_URL, toXml);

			// 处理支付结果
			Map<String, String> params = XPathHelper.toMap(result);
			if (params == null || params.isEmpty()) {
				return new ToPayMsg("0", "查询结果为空", null, null).toString();
			}
			String res = queryPay(params);
			if (!res.equals("ok")) {
				// 还没通知到
				return new ToPayMsg("0", res, null, null).toString();
			}
		}
		UserInfo userInfo = userCashDao.getUserInfo(userCash.getUserId());

		return new ToPayMsg("1", null, userInfo.getE_money(), userInfo.getVip_expiration()).toString();
	}

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		map.put("appid", WxPayConfig.APP_ID);
		map.put("mch_id", WxPayConfig.MCH_ID);
		map.put("out_trade_no", "0fd7e4f42a8b4b4ef33394d35212b13e");
		map.put("nonce_str", UUID.randomUUID().toString().replace("-", "").toLowerCase());

		String sign = getSign(map);

		map.put("sign", sign);

		// 去微信查询
		String toXml = XPathHelper.toXmlNode(map);

		System.out.println(toXml);

		String re = HttpUtils.HttpPostGo(WxPayConfig.PAY_QUERY_URL, toXml);

		System.out.println(re);
	}
}
